package com.qhx.rtkcloud.tcp;

//import javafx.util.Pair;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;

@Component
@Profile({"ntripcaster"})
public class NtripCasterExchangePair extends NtripExchangePair implements InitializingBean {

    public int port;

    public int getPort() {
        return port;
    }

    @Value("${rtk.socketPort}")
    public void setPort(int port) {
        this.port = port;
    }

    public NtripCasterExchangePair() throws IOException {
        super();
    }

    private String getMountFromServer(String info) {
        int slash = info.indexOf("/");
        int lineBreak = info.indexOf("\r\n");
        if (lineBreak == -1) {
            lineBreak = info.indexOf("\n");
        }
        if (slash <= 0 || lineBreak <= 0 || slash >= lineBreak) {
            return null;
        }
        return info.substring(slash + 1, lineBreak);
    }

    private String getMountFromClient(String info) {
        int slash = info.indexOf("/");
        int lineBreak = info.indexOf("\n");
        int http = info.indexOf("HTTP");
        if (slash <= 0 || lineBreak <= 0 || http <= 0 || slash >= lineBreak || slash >= http) {
            return null;
        }
        return info.substring(slash + 1, http).trim();
    }

    private String decodeBase64(String base64) {
        if (StringUtils.isEmpty(base64)) {
            return null;
        }
        byte[] bytes = Base64Utils.decode(base64.getBytes());
        return new String(bytes);
    }

    private static String getUsername(String usernameAndPwd) {
        if (usernameAndPwd == null || usernameAndPwd.length() == 0) {
            return null;
        }

        BitSet bitSet = new BitSet();
        bitSet.toByteArray();
//        int colon = usernameAndPwd.indexOf(":");
//
//        if (colon <= 0) {
//            return null;
//        }

        return usernameAndPwd;

    }


    private String getUsernameFromClient(String info) {

        String startStr = "Authorization: Basic";
        int indexStart = info.indexOf(startStr);
        if (indexStart <= 0) {
            return null;
        }
        int lineBreak = info.indexOf("\n", indexStart);

        return getUsername(decodeBase64(info.substring(indexStart + startStr.length(), lineBreak).trim()));

    }


    private String getMounterAndUsername(String registerInfo) {
        String mount = null;
        String username = null;
        if (registerInfo.startsWith("SOURCE")) {// 基准站过来 Server,需要直接返回成功
            mount = getMountFromServer(registerInfo);

            return mount;
        } else if (registerInfo.startsWith("GET")) {   // 移动站client
            mount = getMountFromClient(registerInfo);
            username = getUsernameFromClient(registerInfo);
            if (mount == null) {
                return null;
            }
            return username == null ? mount.trim() : mount.trim() + "&" + username.trim();
//            map.put(username == null ? mount.trim() : mount.trim() + "&" + username.trim(), false);

          //  return mount == null ? null : new Pair<>(username == null ? mount.trim() : mount.trim() + "&" + username.trim(), false);
        }
        return null;
    }

    private String processAuthInfo(InputStream inputStream) {
        byte[] bytes = new byte[10240];
        int length = 0;
        try {
            if ((length = inputStream.read(bytes)) > 0) {
                String registerInfo = new String(Arrays.copyOfRange(bytes, 0, length));
                return getMounterAndUsername(registerInfo);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void processSocket(Socket socket) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

        String mount = processAuthInfo(inputStream);
        TcpExchangeUnit ntripExchangeUnit = getNtripExchangeUnitMap().get(mount);
        if (ntripExchangeUnit == null) {
            return;
        }

        //判断优先级 是否可以连接

        if (!ntripExchangeUnit.isConnectFreedom() && ntripExchangeUnit.getPartner().isConnectFreedom()
                && (ntripExchangeUnit.getPartner().getClient() == null || ntripExchangeUnit.getPartner().getClient().isClosed())) {
            try {
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }


        ntripExchangeUnit.setClient(socket);
//        if (pair.getValue()) {
        try {
            outputStream.write("ICY 200 OK\r\n".getBytes());
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
//        }


        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
            TcpExchangeUnit tcpExchangeUnit1 = TcpExchangeUnit.TCP_EXCHANGE_UNIT_THREAD_LOCAL.get();
            if (tcpExchangeUnit1 != null && tcpExchangeUnit1.isConnectFreedom()
                    && !tcpExchangeUnit1.getPartner().isConnectFreedom()
                    && tcpExchangeUnit1.getPartner().getClient() != null) {
                try {
                    tcpExchangeUnit1.getPartner().getClient().close();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }

            }
        });
        ntripExchangeUnit.start();
    }

    private void startServer() throws IOException {
        ServerSocket serverSocket = new ServerSocket(port);
        new Thread(() -> {
            try {
                while (true) {
                    Socket socket = serverSocket.accept();
                    new Thread(() -> processSocket(socket), "process:" + port).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, "caster:" + port).start();
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();
        try {
            startServer();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
